#pragma once

namespace hamster
{
  template<typename PairType1, typename PairType2>
  class pair
  {
      public:
          using first_type = PairType1;
          using second_type = PairType2;

          PairType1 first;
          PairType2 second;

          pair() : first(PairType1()), second(PairType2()) {
            //std::cout << __PRETTY_FUNCTION__ << std::endl;
          }

          pair(const PairType1& fir, const PairType2& sec) : first(fir), second(sec) {
            //std::cout << __PRETTY_FUNCTION__ << std::endl;
          }

          // from std::pair to hamster::pair
          pair(const std::pair<PairType1, PairType2>& p) : first(p.first), second(p.second) {
              //std::cout << __PRETTY_FUNCTION__ << std::endl;
          }

          // // 拷贝构造
          pair(const pair<PairType1, PairType2>& other_pair) 
          : first(other_pair.first), second(other_pair.second)
          {
            // std::cout << __PRETTY_FUNCTION__ << std::endl;
              // first = other_pair.first;
              // second = other_pair.second;
          }

          // // 移动构造
          pair(pair<PairType1, PairType2>&& other_pair) noexcept
          : first(std::move(other_pair.first)), second(std::move(other_pair.second)){
              // first = std::move(other_pair.first);
              // second = std::move(other_pair.second);
          }

          // // 拷贝赋值
          // pair& operator=(const pair<PairType1, PairType2>& other_pair) {
          //     if (this != &other_pair) {
          //         first = other_pair.first;
          //         second = other_pair.second;
          //     }
          //     return *this;
          // }

          // // 移动赋值
          // pair& operator=(pair<PairType1, PairType2>&& other_pair) noexcept {
          //     if (this != &other_pair) {
          //         first = std::move(other_pair.first);
          //         second = std::move(other_pair.second);
          //     }
          //     return *this;
          // 

          // 如果这里进行类型推导了，map中的pair中有const 成员，那么就办法使用拷贝赋值和移动赋值了
          // 所以最好的办法就是不定义这些函数，再实例化pair时候，由编译器帮我们定义这些函数
          // 对于有const成员的pair,编译器就会帮忙把赋值相关函数删除
  };

  template <class _T1, class _T2>
  inline bool operator==(const pair<_T1, _T2>& __x, const pair<_T1, _T2>& __y)
  { 
    return __x.first == __y.first && __x.second == __y.second; 
  }

  template <class _T1, class _T2>
  inline bool operator<(const pair<_T1, _T2>& __x, const pair<_T1, _T2>& __y)
  { 
    return __x.first < __y.first || 
          (!(__y.first < __x.first) && __x.second < __y.second); 
  }

  template <class _T1, class _T2>
  inline bool operator!=(const pair<_T1, _T2>& __x, const pair<_T1, _T2>& __y) {
    return !(__x == __y);
  }

  template <class _T1, class _T2>
  inline bool operator>(const pair<_T1, _T2>& __x, const pair<_T1, _T2>& __y) {
    return __y < __x;
  }

  template <class _T1, class _T2>
  inline bool operator<=(const pair<_T1, _T2>& __x, const pair<_T1, _T2>& __y) {
    return !(__y < __x);
  }

  template <class _T1, class _T2>
  inline bool operator>=(const pair<_T1, _T2>& __x, const pair<_T1, _T2>& __y) {
    return !(__x < __y);
  }

  // Inline Function - Make Pair
  template<typename PairType1, typename PairType2>
  inline pair<PairType1, PairType2> make_pair(const PairType1& fir, const PairType2& sec)
  {
      return pair<PairType1, PairType2>(fir, sec);
  }
}
